﻿using CaseManagerLibrary.Models;
using CaseManagerLibrary.Socket;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace SmartLight
{
    /// <summary>
    /// Smart Light管理器
    /// </summary>
    public class SmartLightManager
    {
        /// <summary>
        /// 设备远程TCP通讯地址
        /// </summary>
        public IPEndPoint RemoteEP { get; set; }

        /// <summary>
        /// 音频文件列表
        /// </summary>
        public List<AudioInfo> AudioList { get; private set; }

        Socket clientSocket;
        public SmartLightManager()
        {
            AudioList = new List<AudioInfo>();

            clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

        }

        /// <summary>
        /// 根据音频id获取音频信息
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public AudioInfo GetAudio(int id)
        {
            return AudioList.Where(t => t.id == id).FirstOrDefault();
        }

        /// <summary>
        /// 根据名称获取音频信息
        /// </summary>
        /// <param name="name"></param>
        /// <returns></returns>
        public AudioInfo GetAudio(string name)
        {
            return AudioList.Where(t => t.name == name).FirstOrDefault();
        }

        /// <summary>
        /// 连接smart light设备
        /// </summary>
        /// <param name="ip"></param>
        /// <param name="port"></param>
        /// <returns></returns>
        public HResult Connect(string ip, int port)
        {
            RemoteEP = new IPEndPoint(IPAddress.Parse(ip), port);

            if (clientSocket.Connected)
                clientSocket.Close();

            HResult ret = new HResult();
            try
            {
                clientSocket.Connect(RemoteEP);
                ret.success = true;
                ret.message = "device connected";
            }
            catch (Exception ex)
            {
                ret.success = false;
                ret.message = ex.Message;
            }

            return ret;
        }



        /// <summary>
        /// 复位设备芯片
        /// </summary>
        public HResult Reset(int wait = 0)
        {
            string cmd = "01 06 00 0C 00 00";

            var ret = SendCommand(cmd);

            if (wait > 0)
            {
                Thread.Sleep(wait * 1000);
            }

            return ret;

        }

        /// <summary>
        /// 关闭亮灯
        /// </summary>
        public HResult LightOff(int wait = 0)
        {
            string cmd = "01 06 00 C2 00 60";

            var ret = SendCommand(cmd);

            if (wait > 0)
            {
                Thread.Sleep(wait * 1000);
            }

            return ret;

        }

        /// <summary>
        /// 仅亮灯，不播放声音
        /// </summary>
        /// <param name="color">亮灯颜色</param>
        /// <param name="lightType">亮灯方式</param>
        /// <param name="wait">执行后等待时间（秒）</param>
        public HResult LightWithOutSound(LightColor color, LightType lightType, int wait = 0)
        {
            string cmd = $"01 06 00 C2 00 {(int)lightType}{(int)color}";

            var ret = SendCommand(cmd);

            if (wait > 0)
            {
                Thread.Sleep(wait * 1000);
            }

            return ret;
        }

        /// <summary>
        /// 亮灯并播放声音
        /// </summary>
        /// <param name="color">亮灯颜色</param>
        /// <param name="lightType">亮灯方式</param>
        /// <param name="audioId">音频id</param>
        /// <param name="soundPlay">播放方式</param>
        /// <param name="wait">执行后等待时间（秒）</param>
        /// <returns></returns>
        public HResult LightWithSound(LightColor color, LightType lightType, int audioId, SoundPlay soundPlay, int wait = 0)
        {
            //01 06 12 03 00 02
            string cmd = $"01 06 {(int)lightType}{(int)color} {(soundPlay == SoundPlay.ONCE ? "03" : "08")} 00 {DecToHex(audioId)}";

            var ret = SendCommand(cmd);

            if (wait > 0)
            {
                Thread.Sleep(wait * 1000);
            }

            return ret;
        }

        /// <summary>
        ///  停止播放声音
        /// </summary>
        /// <param name="wait">执行后等待时间</param>
        /// <returns></returns>
        public HResult StopSound(int wait = 0)
        {
            string cmd = "01 06 00 16 00 01";

            var ret = SendCommand(cmd);

            if (wait > 0)
            {
                Thread.Sleep(wait * 1000);
            }

            return ret;
        }

        /// <summary>
        /// 仅播放声音，不亮灯
        /// </summary>
        /// <param name="audioId">音频id</param>
        /// <param name="wait">执行后等待时间（秒）</param>
        /// <returns></returns>
        public HResult Sound(int audioId, int wait = 0)
        {
            string cmd = $"01 06 60 03 00 {DecToHex(audioId)}";

            var ret = SendCommand(cmd);

            if (wait > 0)
            {
                Thread.Sleep(wait * 1000);
            }

            return ret;
        }

        /// <summary>
        /// 设置设备音量
        /// </summary>
        /// <param name="vol">音量值1-30</param>
        /// <returns></returns>
        public HResult SetVolume(int vol)
        {
            string cmd = $"01 06 00 06 00 {DecToHex(vol)}";

            var ret = SendCommand(cmd);

            return ret;
        }

        /// <summary>
        /// 获取设备当前音量
        /// </summary>
        /// <returns></returns>
        public int GetVolume()
        {
            string cmd = "FF 03 00 43 00 00";

            var ret = SendCommand(cmd, true);

            byte[] data = (byte[])ret.data;

            int vol = HexToDec(data, 4);

            return vol;
        }


        /// <summary>
        /// 十进制转十六进制字符串
        /// </summary>
        /// <param name="d"></param>
        /// <returns></returns>
        private string DecToHex(int d)
        {
            return d.ToString("X2");
        }

        /// <summary>
        /// 十六进制字节数组转十进制
        /// </summary>
        /// <param name="buffer">字节数组</param>
        /// <param name="index">要转换的数组第几位</param>
        /// <returns></returns>
        private int HexToDec(byte[] buffer, int index)
        {
            string hex = ((int)buffer[index]).ToString("X2");

            int dec = Convert.ToInt32(hex, 16);

            return dec;
        }

        /// <summary>
        /// 十六进制字符串转字节数组
        /// </summary>
        /// <param name="hexString"></param>
        /// <returns></returns>
        private byte[] HexStrTobyte(string hexString)
        {
            hexString = hexString.Replace(" ", "");
            if ((hexString.Length % 2) != 0)
                hexString += " ";
            byte[] returnBytes = new byte[hexString.Length / 2];
            for (int i = 0; i < returnBytes.Length; i++)
                returnBytes[i] = Convert.ToByte(hexString.Substring(i * 2, 2).Trim(), 16);
            return returnBytes;
        }

        /// <summary>
        /// 字节数组转十六进制字符串
        /// </summary>
        /// <param name="buffer"></param>
        /// <returns></returns>
        private string ByteToHexString(byte[] buffer)
        {
            StringBuilder strBuider = new StringBuilder();
            for (int index = 0; index < buffer.Length; index++)
            {
                if (index > 0)
                    strBuider.Append(" ");

                strBuider.Append(((int)buffer[index]).ToString("X2"));
            }

            return strBuider.ToString();
        }

        /// <summary>
        /// 返回MODBUS CRC16校验值
        /// </summary>
        /// <param name="data">被检验的数据</param>
        /// <returns></returns>
        private byte[] CRC16(byte[] data)
        {
            int len = data.Length;
            if (len > 0)
            {
                ushort crc = 0xFFFF;

                for (int i = 0; i < len; i++)
                {
                    crc = (ushort)(crc ^ (data[i]));
                    for (int j = 0; j < 8; j++)
                    {
                        crc = (crc & 1) != 0 ? (ushort)((crc >> 1) ^ 0xA001) : (ushort)(crc >> 1);
                    }
                }
                byte hi = (byte)((crc & 0xFF00) >> 8);  //高位置
                byte lo = (byte)(crc & 0x00FF);         //低位置

                return new byte[] { lo, hi };
            }
            return new byte[] { 0, 0 };
        }


        /// <summary>
        /// 合并数据和CRC16校验值
        /// </summary>
        /// <param name="data">数据</param>
        /// <param name="crc">校验值</param>
        /// <returns></returns>
        private byte[] MergeByteArray(byte[] data, byte[] crc)
        {
            List<byte> listData = new List<byte>();
            listData.AddRange(data);
            listData.AddRange(crc);
            byte[] byteData = listData.ToArray();
            return byteData;
        }

        /// <summary>
        /// 向设备发送MODBUS命令数据
        /// </summary>
        /// <param name="cmd">modbus命令</param>
        /// <param name="rec">是否接收设备返回值</param>
        /// <returns></returns>
        private HResult SendCommand(string cmd, bool rec = false)
        {
            if (RemoteEP == null)
                return new HResult() { success = false, message = "未设置远程设备地址！" };

            byte[] buffer = HexStrTobyte(cmd);

            byte[] crc = CRC16(buffer);

            byte[] data = MergeByteArray(buffer, crc);

            HResult ret = new HResult();

            try
            {
                clientSocket.Send(data);

                if (rec)
                {
                    byte[] recByte = new byte[8];
                    clientSocket.Receive(recByte);

                    ret.data = recByte;
                }

                ret.success = true;
                ret.message = "send: " + ByteToHexString(data);
            }
            catch (Exception ex)
            {
                ret.success = false;
                ret.message = "send: " + ByteToHexString(data) + " error: " + ex.Message;
            }

            return ret;
        }

        /// <summary>
        /// 关闭设备连接
        /// </summary>
        public void Close()
        {
            clientSocket.Close();
        }

    }

    /// <summary>
    /// 亮灯颜色
    /// </summary>
    public enum LightColor : int
    {
        /// <summary>
        /// 红灯
        /// </summary>
        RED = 1,
        /// <summary>
        /// 黄灯
        /// </summary>
        YELLOW = 2,
        /// <summary>
        /// 绿灯
        /// </summary>
        GREEN = 3,
    }

    /// <summary>
    /// 亮灯方式
    /// </summary>
    public enum LightType : int
    {
        /// <summary>
        /// 熄灭 
        /// </summary>
        OFF = 0,
        /// <summary>
        /// 常亮
        /// </summary>
        NORMAL = 1,
        /// <summary>
        /// 慢闪
        /// </summary>
        SLOW_FLASH = 2,
        /// <summary>
        /// 快闪
        /// </summary>
        QUICK_FLASH = 3,
    }

    /// <summary>
    /// 播报方式
    /// </summary>
    public enum SoundPlay : int
    {
        /// <summary>
        /// 播放一次
        /// </summary>
        ONCE = 0,
        /// <summary>
        /// 循环播放
        /// </summary>
        LOOP = 1,
        /// <summary>
        /// 停止播放
        /// </summary>
        STOP = 2,
    }


}
